/*
 * ConceptExtractor.java
 *
 * Created on 10 April 2007, 15:16
 *
 *
 */

package rxtokenizer;

import java.util.*;
import java.util.regex.*;
import java.io.*;

/**
 * Class for extracting information
 * @author ruslan
 */
public class ConceptExtractor {
    
    public ConceptExtractor(ConceptTypeContainer conceptTypes, IDocument document) {
	this.conceptTypes = conceptTypes;
	this.document = document;
    }
    
    public Result extract(File aFile) throws FileNotFoundException, IOException {
        BufferedReader input =  new BufferedReader(new FileReader(aFile));
        LinkedList concepts = new LinkedList();
        String line = null;
        Result res = Result.NO_ERROR;
        while (( line = input.readLine()) != null){
            line = line.trim();
            if (line.length()>0) {
                res = extract(line);
                if (this.concepts != null)
                	concepts.addAll(this.concepts);
                if (res != Result.NO_ERROR) {
                    input.close();
                    return res;
                }
            }
        }
        this.concepts = (concepts.size() > 0)? concepts: null;
        input.close();
        return res;
    }
    
    public Result extract(List conceptNames) {
    	LinkedList concepts = new LinkedList();
        Result res = Result.NO_ERROR;
        Iterator iter = conceptNames.iterator();
        while (iter.hasNext()) {
            String conceptName = (String) iter.next();
            res = extract(conceptName);
            if (this.concepts != null)
            	concepts.addAll(this.concepts);
            if (res != Result.NO_ERROR)
                return res;
        }
        this.concepts = (concepts.size() > 0)? concepts: null;
        return res;
    }
    
    public Result extract(String name) {
	ConceptType ct = conceptTypes.getConceptTypeByName(name);
	if (ct == null) return Result.ERROR_05;
	return extract(ct);
    }
    
    public Result extract(ConceptType conceptType) {
	if ( !(conceptType instanceof RegExpConceptType) )
	    return Result.ERROR_02;
	RegExpConceptType rxct = (RegExpConceptType) conceptType;
	Pattern pttrn = Pattern.compile(rxct.getRegExp());
	Matcher mtchr = pttrn.matcher(document.getText());
	LinkedList concepts = new LinkedList();
	while (mtchr.find())
	    if (CheckingRegExpConcept(rxct, mtchr, 0))
		concepts.add(new Concept(mtchr.start(), mtchr.end(), document, conceptType));
	this.concepts = (concepts.size() > 0)? concepts: null;
	return Result.NO_ERROR;
    }
    
    private boolean CheckingRegExpConcept(ConceptType conceptType, Matcher matcher, int deltaGroup) {
	if (conceptType.getConstraints() == null) return true;
	Iterator iter = conceptType.getConstraints().iterator();
	ExtractiveConcept extractiveConcept;
	String conceptValue = null;
	while (iter.hasNext()) {
	    extractiveConcept = (ExtractiveConcept) iter.next();
	    try {
		conceptValue = matcher.group(extractiveConcept.getGroupNum() + deltaGroup);
	    }
	    catch (IndexOutOfBoundsException ex) {
		continue;
	    }
	    if (conceptValue == null)
		continue;
	    if (!extractiveConcept.isClear()) {
		int i = conceptValue.length();
		if (extractiveConcept.isLengthSet())
		    if (i != extractiveConcept.getLength())
			return false;
		if (extractiveConcept.isMinLengthSet())
		    if (i < extractiveConcept.getMinLength())
			return false;
		if (extractiveConcept.isMaxLengthSet())
		    if (i > extractiveConcept.getMaxLength())
			return false;
		if (extractiveConcept.isContaintsSet())
		    if (!conceptValue.contains(extractiveConcept.getContaints()))
			return false;
		if (extractiveConcept.isStartsWithSet())
		    if (!conceptValue.startsWith(extractiveConcept.getStartsWith()))
			return false;
		if (extractiveConcept.isEndsWithSet())
		    if (!conceptValue.endsWith(extractiveConcept.getEndsWith()))
			return false;
		if (extractiveConcept.isValueSet())
		    if (!conceptValue.equals(extractiveConcept.getValue()))
			return false;
		double d;
		try {
		    d = Double.parseDouble(conceptValue);
		}
		catch (NumberFormatException ex) {
		    d = Double.NaN;
		}
		if (extractiveConcept.isNumValueSet())
		    if ( (Double.isNaN(d))||(d != extractiveConcept.getNumValue()) )
			return false;
		if (extractiveConcept.isMinValueSet()){
		    if ( (Double.isNaN(d))||(d < extractiveConcept.getMinValue()) )
			return false;
		}
		if (extractiveConcept.isMaxValueSet())
		    if ( (Double.isNaN(d))||(d > extractiveConcept.getMaxValue()) )
			return false;
	    }
	    else if (extractiveConcept.getTypeInfo() != conceptType) {
		if (! CheckingRegExpConcept(extractiveConcept.getTypeInfo(), matcher, extractiveConcept.getGroupNum() + deltaGroup))
		    return false;
	    }
	}
	return true;
    }
    
    public LinkedList getConcepts(){
        return concepts;
    }
    
    public ConceptTypeContainer getConceptTypes(){
        return conceptTypes;
    }
     
     public void setConceptTypes(ConceptTypeContainer conceptTypes){
        this.conceptTypes = conceptTypes;
    }

    public IDocument getDocument(){
        return document;
    }
     
     public void setDocument(IDocument document){
        this.document = document;
    }
    
	/**
	 * List of concept types
	 */
    private ConceptTypeContainer conceptTypes = null;
	/**
	 * Source of text content
	 */
    private IDocument document = null;
	/**
	 * extracted concepts
	 */
    private LinkedList concepts = null;

}
